/**
 * Fuzzy Refrigerator: Refrigerator with Fuzzy Logic as temperature controller
 * Copyright (C) 2012  Izwan Azmi
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

 /**
  * @file mamdani.cpp
  * @brief
  * @author Izwan Azmi <izwanazmi90@gmail.com>
  */

  #include "mamdani.h"

mamdani::mamdani() {
    //ctor
}

mamdani::~mamdani() {
    //dtor
}

float mamdani::clipped(float out[], trapezoid trz[], int saiz) {
    float interX;
    float interY;

    for(int i = 0; i < saiz; i++) {
        switch (trz[i].jt) {
        case kiri:
            cl[i].lim_atas = out[i];
            cl[i].lim_kiri = trz[i].a;

            interX = interceptX(trz[i], trz[i + 1], kiri);    // Cari pintasan X
            interY = fuzzification(interX, trz[i]);  // Cari pintasan Y

            /**
             * output i >= interception Y and output i + 1 >= interception Y
             * ^___        ___________
             * |   \      /           \
             * |####\    /             \
             * |#####\  /###############\
             * |######\/#################\
             * |######/\##################\
             * |#####/##\##################\
             * |####/####\##################\
             * ------------------------------------->
             */
            if(out[i] >= interY && out[i + 1] >= interY)
                cl[i].lim_kanan = interX;

            /**
             * output i > output i + 1 and output i + 1 < interception Y
             * ^___        ___________
             * |   \      /           \
             * |####\    /             \
             * |#####\  /               \
             * |######\/                 \
             * |######/\                  \
             * |#####/##\##################\
             * |####/####\##################\
             * ------------------------------------->
             */
            else if(out[i] > out[i + 1] && out[i + 1] < interY)
                cl[i].lim_kanan = (out[i + 1] / trz[i].cerun_kanan) + trz[i].b;

            /**
             * output i < output i + 1 and output i < interception Y
             * ^___        ___________
             * |   \      /           \
             * |    \    /#############\
             * |     \  /###############\
             * |      \/#################\
             * |      /\##################\
             * |#####/##\##################\
             * |####/####\##################\
             * ------------------------------------->
             */
            else if(out[i] < out[i + 1] && out[i] < interY)
                cl[i].lim_kanan = (out[i] / trz[i + 1].cerun_kiri) + trz[i].a;

            else cl[i].lim_kanan = 10101;
            break;

        case kanan:
            cl[i].lim_atas = out[i];
            cl[i].lim_kanan = trz[i].b;

            interX = interceptX(trz[i - 1], trz[i], kanan);    // Cari pintasan X
            interY = fuzzification(interX, trz[i]);  // Cari pintasan Y

            /**
             * output i >= interception Y and output i - 1 >= interception Y
             * ^       ___________      ___________
             * |      /           \    /
             * |     /             \  /############
             * |    /###############\/#############
             * |   /################/\#############
             * |  /################/##\############
             * | /################/####\###########
             * |/################/######\##########
             * ------------------------------------->
             */
            if(out[i] >= interY && out[i - 1] >= interY)
                cl[i].lim_kiri = interX;

            /**
             * output i > output i - 1 and output i - 1 < interception Y
             * ^       ___________      ___________
             * |      /           \    /
             * |     /             \  /############
             * |    /               \/#############
             * |   /                /\#############
             * |  /                /##\############
             * | /################/####\###########
             * |/################/######\##########
             * ------------------------------------->
             */
            else if(out[i] > out[i - 1] && out[i - 1] < interY)
                cl[i].lim_kiri = (out[i - 1] / trz[i].cerun_kiri) + trz[i].a;

            /**
             * output i < output i - 1 and output i < interception Y
             * ^       ___________      ___________
             * |      /           \    /
             * |     /#############\  /
             * |    /###############\/
             * |   /################/\
             * |  /################/##\
             * | /################/####\###########
             * |/################/######\##########
             * ------------------------------------->
             */
            else if(out[i] < out[i - 1] && out[i] < interY)
                cl[i].lim_kiri = (out[i] / trz[i - 1].cerun_kanan) + trz[i - 1].d;

            else cl[i].lim_kiri = 10101;
            break;

        case biasa:
            cl[i].lim_atas = out[i];

            interX = interceptX(trz[i - 1], trz[i], biasa);    // Cari pintasan X
            interY = fuzzification(interX, trz[i]);  // Cari pintasan Y

            /**
             * output i >= interception Y and output i - 1 >= interception Y
             * ^       ___________      ___________
             * |      /           \    /
             * |     /             \  /############
             * |    /###############\/#############
             * |   /################/\#############
             * |  /################/##\############
             * | /################/####\###########
             * |/################/######\##########
             * ------------------------------------->
             */
            if(out[i] >= interY && out[i - 1] >= interY) {
                cl[i].lim_kiri = interX;
            }

            /**
             * output i > output i - 1 and output i - 1 < interception Y
             * ^       ___________      ___________
             * |      /           \    /
             * |     /             \  /############
             * |    /               \/#############
             * |   /                /\#############
             * |  /                /##\############
             * | /################/####\###########
             * |/################/######\##########
             * ------------------------------------->
             */
            else if(out[i] > out[i - 1] && out[i - 1] < interY)
                cl[i].lim_kiri = (out[i - 1] / trz[i].cerun_kiri) + trz[i].a;

            /**
             * output i < output i - 1 and output i < interception Y
             * ^       ___________      ___________
             * |      /           \    /
             * |     /#############\  /
             * |    /###############\/
             * |   /################/\
             * |  /################/##\
             * | /################/####\###########
             * |/################/######\##########
             * ------------------------------------->
             */
            else if(out[i] < out[i - 1] && out[i] < interY)
                cl[i].lim_kiri = (out[i] / trz[i - 1].cerun_kanan) + trz[i - 1].b;

            else cl[i].lim_kiri = 10101;

            interX = interceptX(trz[i], trz[i + 1], biasa);    // Cari pintasan X
            interY = fuzzification(interX, trz[i]);  // Cari pintasan Y

            /**
             * output i >= interception Y and output i + 1 >= interception Y
             * ^___        ___________
             * |   \      /           \
             * |####\    /             \
             * |#####\  /###############\
             * |######\/#################\
             * |######/\##################\
             * |#####/##\##################\
             * |####/####\##################\
             * ------------------------------------->
             */
            if(out[i] >= interY && out[i + 1] >= interY)
                cl[i].lim_kanan = interX;

            /**
             * output i > output i + 1 and output i + 1 < interception Y
             * ^___        ___________
             * |   \      /           \
             * |####\    /             \
             * |#####\  /               \
             * |######\/                 \
             * |######/\                  \
             * |#####/##\##################\
             * |####/####\##################\
             * ------------------------------------->
             */
            else if(out[i] > out[i + 1] && out[i + 1] < interY)
                cl[i].lim_kanan = (out[i + 1] / trz[i].cerun_kanan) + trz[i].d;

            /**
             * output i < output i + 1 and output i < interception Y
             * ^___        ___________
             * |   \      /           \
             * |    \    /#############\
             * |     \  /###############\
             * |      \/#################\
             * |      /\##################\
             * |#####/##\##################\
             * |####/####\##################\
             * ------------------------------------->
             */
            else if(out[i] < out[i + 1] && out[i] < interY)
                cl[i].lim_kanan = (out[i] / trz[i + 1].cerun_kiri) + trz[i].a;

            else cl[i].lim_kanan = 10101;
            break;
        }
    }

    return 10101;
}

float mamdani::interceptX(trapezoid a, trapezoid b, jenis_trapz jt) {
    if(jt == kiri)
        return ((a.cerun_kanan * a.b) - (b.cerun_kiri * b.a)) / (a.cerun_kanan - b.cerun_kiri);
    else if (jt == kanan)
        return ((a.cerun_kanan * a.d) - (b.cerun_kiri * b.a)) / (a.cerun_kanan - b.cerun_kiri);
    else if (jt == biasa) {
        if(a.c == 0 && a.d == 0 && b.c != 0 && b.d != 0)
            return ((a.cerun_kanan * a.b) - (b.cerun_kiri * b.a)) / (a.cerun_kanan - b.cerun_kiri);
        else if(a.c != 0 && a.d != 0 && b.c == 0 && b.d == 0)
            return ((a.cerun_kanan * a.d) - (b.cerun_kiri * b.a)) / (a.cerun_kanan - b.cerun_kiri);
        else return 10101;
    } else return 10101;
}

float mamdani::defuzzification(trapezoid trz[], float out[], float min, float max, float saiz, int outSize) {
    float sumNominator = 0;
    float sumDenominator = 0;

    for(int i = 0; i < outSize; i++) {
        for(float j = cl[i].lim_kiri; j <= cl[i].lim_kanan; j += saiz) {
            if(fuzzification(j, trz[i]) > out[i]) {
                sumNominator = sumNominator +(j * out[i]);
                sumDenominator = sumDenominator + out[i];
            } else {
                sumNominator = sumNominator +(j * fuzzification(j, trz[i]));
                sumDenominator = sumDenominator + fuzzification(j, trz[i]);
            }
        }
    }

    return sumNominator / sumDenominator;
}





